package cn.broadmax.boot.util;

import cn.broadmax.boot.base.model.LoginUser;
import lombok.extern.slf4j.Slf4j;

import java.util.HashMap;
import java.util.Map;

/**
 * ThreadLocal统一容器
 * @author jeff
 * @date 2020/7/20
 */
@Slf4j
public abstract class ThreadLocalContext {

    private static final String SUBJECT_KEY = ThreadLocalContext.class.getName() + "_SUBJECT_KEY";

    private static final ThreadLocal<Map<String, Object>> local = new ThreadLocal<>();

    protected ThreadLocalContext() {
    }

    private static Object getValue(String key) {
        Map<String, Object> perThreadResources = local.get();
        return perThreadResources != null ? perThreadResources.get(key) : null;
    }

    public static Object get(String key) {
        if (log.isTraceEnabled()) {
            String msg = "get() - in thread [" + Thread.currentThread().getName() + "]";
            log.trace(msg);
        }

        Object value = getValue(key);
        if (value != null && log.isTraceEnabled()) {
            log.trace("Retrieved value of type [{}] for key [{}] bound to thread [{}]", value.getClass().getName(), key, Thread.currentThread().getName());
        }
        return value;
    }

    public static void put(String key, Object value) {
        if (key == null) {
            throw new IllegalArgumentException("key cannot be null");
        }

        if (value == null) {
            remove(key);
            return;
        }

        ensureResourcesInitialized();
        local.get().put(key, value);

        if (log.isTraceEnabled()) {
            log.trace("Bound value of type [{}] for key [{}] to thread [{}]", value.getClass().getName(), key, Thread.currentThread().getName());
        }
    }

    public static Object remove(String key) {
        Map<String, Object> perThreadResources = local.get();
        Object value = perThreadResources != null ? perThreadResources.remove(key) : null;

        if ((value != null) && log.isTraceEnabled()) {
            log.trace("Removed value of type [{}] for key [{}] from thread [{}]", value.getClass().getName(), key, Thread.currentThread().getName());
        }
        return value;
    }

    public static LoginUser getSubject() {
        return (LoginUser) get(SUBJECT_KEY);
    }

    public static void bind(LoginUser subject) {
        if (subject != null) {
            put(SUBJECT_KEY, subject);
        }
    }

    private static void ensureResourcesInitialized(){
        if (local.get() == null){
            local.set(new HashMap<>());
        }
    }


}
